package com.luboyan.CBillbill.service.user.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.luboyan.CBillbill.advice.TokenVerify;
import com.luboyan.CBillbill.mapper.user.following.UserFollowingMapper;
import com.luboyan.CBillbill.dao.file.Video;
import com.luboyan.CBillbill.dao.user.RefreshToken;
import com.luboyan.CBillbill.dao.user.following.UserFollowing;
import com.luboyan.CBillbill.dao.vo.PageVo;
import com.luboyan.CBillbill.service.file.VideoService;
import com.luboyan.CBillbill.service.user.UserRefreshService;
import com.luboyan.CBillbill.service.user.auth.UserAuthService;
import com.luboyan.CBillbill.util.enums.UserInfoEnum;
import com.luboyan.CBillbill.exception.ConditionException;
import com.luboyan.CBillbill.mapper.user.UserInfoMapper;
import com.luboyan.CBillbill.mapper.user.UserMapper;
import com.luboyan.CBillbill.dao.user.User;
import com.luboyan.CBillbill.dao.user.UserInfo;
import com.luboyan.CBillbill.service.user.UserService;
import com.luboyan.CBillbill.util.JwtHelper;
import com.luboyan.CBillbill.util.encrypt.MD5Util;
import com.luboyan.CBillbill.util.encrypt.RSAUtil;
import com.mysql.cj.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 用户登录信息业务逻辑实现
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserFollowingMapper userFollowingMapper;

    @Autowired
    private UserAuthService userAuthService;

    @Autowired
    private UserRefreshService userRefreshService;

    @Autowired
    private VideoService videoService;

    @Autowired
    private TokenVerify tokenVerify;

    /**
     * 用户的注册
     *
     * @param user 前端传来的用户信息
     */
    @Override
    @Transactional
    public void addUser(User user) {
        String phone = user.getPhone();
        if (StringUtils.isNullOrEmpty(phone)) {
            throw new ConditionException("手机号输入为空！");
        }

        Exist<User> userExist = new Exist<>();
        if (userExist.isExist(userMapper, "phone", phone)) {
            throw new ConditionException("手机号已被注册！");
        }

        if (user.getEmail() != null) {
            if (userExist.isExist(userMapper, "email", user.getEmail())) {
                throw new ConditionException("邮箱已被注册！");
            }
        }


        Date nowTime = new Date();
        String salt = String.valueOf(nowTime.getTime()); //准备对密码进行md5加密需要的盐值
        String password = user.getPassword();
        String rsaPassword;
        try {
            rsaPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        String Md5Password = MD5Util.sign(rsaPassword, salt, "UTF-8");
        user.setPassword(Md5Password);
        user.setCreateTime(nowTime);
        user.setSalt(salt);
        userMapper.insert(user);

        //同时userinfo中也需要新增信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick("萌新");
        userInfo.setGender(UserInfoEnum.GENDER_UNKNOW.getParameter());
        userInfo.setBirth(UserInfoEnum.DEFAULT_BIRTH.getParameter());
        userInfo.setCreateTime(nowTime);
        userInfoMapper.insert(userInfo);


        //给用户添加默认角色
        userAuthService.addUserDefaultRole(user.getId());

    }

    /**
     * 登录
     */
    @Override
    public String login(User user) {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)) {
            throw new ConditionException("账号输入为空！");
        }
        //有多少个字段凭借就支持多少种登录方式
        String phoneOrEmail = phone + email;
        User dbuser = userMapper.selectByPhoneOrEmail(phoneOrEmail);

        if (dbuser == null) {
            throw new ConditionException("用户不存在！");
        }
        String password = user.getPassword();
        String rsaPassword;
        try {
            rsaPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        String salt = dbuser.getSalt();
        String Md5Password = MD5Util.sign(rsaPassword, salt, "UTF-8");
        if (!Md5Password.equals(dbuser.getPassword())) {
            throw new ConditionException("密码错误！");
        }

        return JwtHelper.createToken(dbuser.getId());
    }

    /**
     * 通过单个id获取用户账号信息
     */
    @Override
    public User getUserInfo(Long userId) {
        User user = userMapper.selectById(userId);
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        userInfoQueryWrapper.eq("userid", userId);
        UserInfo userInfo = userInfoMapper.selectOne(userInfoQueryWrapper);
        user.setUserInfo(userInfo);
        return user;
    }

    /**
     * 更新用户账号信息
     */
    @Override
    public void updateUser(User user) throws Exception {
        User dbuser = userMapper.selectById(user.getId());
        if (dbuser == null) {
            throw new ConditionException("用户不存在！");
        }
        if (!StringUtils.isNullOrEmpty(user.getPassword())) {
            String rawPassword = RSAUtil.decrypt(user.getPassword());
            String md5Password = MD5Util.sign(rawPassword, dbuser.getSalt(), "UTF-8");
            user.setPassword(md5Password);
        }
        user.setUpdateTime(new Date());
        userMapper.updateById(user);
    }

    /**
     * 更新用户基本信息
     */
    @Override
    public void updateUserInfo(UserInfo userInfo) {
        userInfo.setUpdateTime(new Date());
        QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<>();
        QueryWrapper<UserInfo> userId = userInfoQueryWrapper.eq("userId", userInfo.getUserId());
        userInfoMapper.update(userInfo, userId);
//        userInfoMapper.updateById(userInfo);
    }

    /**
     * 通过id查询用户
     */
    @Override
    public User getById(Long id) {
        return userMapper.selectById(id);
    }

    /**
     * 通过id批量查询用户基本信息
     */
    @Override
    public List<UserInfo> getUserInfoByIds(Set<Long> followingIds) {
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("userId", followingIds);
        return userInfoMapper.selectList(queryWrapper);
    }

    /**
     * 分页获取用户信息，用于在搜索后展示，还可以顺便判断是否被当前用户关注
     */
    @Override
    public PageVo<UserInfo> getPageUserInfos(JSONObject params) {
        Integer page = params.getInteger("page");
        Integer pageSize = params.getInteger("pageSize");
        params.put("pageStar", (page - 1) * pageSize);
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        String nick = params.getString("nick");
        if (nick != null && !Objects.equals(nick, "")) {
            queryWrapper.like("nick", nick);
        }
        Long rows = userInfoMapper.selectCount(queryWrapper); //获取匹配的总条数
        List<UserInfo> userInfoList = new ArrayList<>(); //总条数为0就返回一个空列表
        if (rows > 0) {
            userInfoList = userInfoMapper.getPageUserInfos(params);
            //判断用户是否被当前用户已关注
            Long userId = params.getLong("userId");
            List<UserFollowing> userFollowings = userFollowingMapper
                    .selectList(new QueryWrapper<UserFollowing>().eq("userId", userId));
            for (UserInfo userInfo : userInfoList) {
                userInfo.setFollowed(false);
                for (UserFollowing userFollowing : userFollowings) {
                    if (userFollowing.getFollowingId().equals(userInfo.getUserId())) {
                        userInfo.setFollowed(true);
                        break;
                    }
                }
            }
        }
        return new PageVo<>(Integer.parseInt(Long.toString(rows)), userInfoList);
    }

    /**
     * 双token登录机制
     */
    @Override
    public Map<String, Object> dLogin(User user) {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isNullOrEmpty(phone) && StringUtils.isNullOrEmpty(email)) {
            throw new ConditionException("账号输入为空！");
        }
        //有多少个字段凭借就支持多少种登录方式
        String phoneOrEmail = phone + email;
        User dbuser = userMapper.selectByPhoneOrEmail(phoneOrEmail);

        if (dbuser == null) {
            throw new ConditionException("用户不存在！");
        }
        String password = user.getPassword();
        String rsaPassword;
        try {
            rsaPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        String salt = dbuser.getSalt();
        String Md5Password = MD5Util.sign(rsaPassword, salt, "UTF-8");
        if (!Md5Password.equals(dbuser.getPassword())) {
            throw new ConditionException("密码错误！");
        }
        Long id = dbuser.getId();
        String token = JwtHelper.createToken(id);
        String refreshToken = JwtHelper.createRefreshToken(id);
//        userRefreshService.deleteRefreshTokenById(id);
        userRefreshService.addRefreshTokenById(id, refreshToken, new Date());
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", token);
        result.put("refreshToken", refreshToken);
        return result;
    }

    /**
     * 退出登录
     */
    @Override
    public void logout(String refreshToken) {
        userRefreshService.deleteRefreshToken(refreshToken);
    }

    /**
     * 刷新token
     */
    @Override
    public String refreshToken(String refreshToken) {
        RefreshToken userRefresh = userRefreshService.getRefreshToken(refreshToken);
        if(userRefresh == null){
            throw new ConditionException("512", "reToken过期！");
        }
        Long userId = JwtHelper.verifyReToken(refreshToken);
//        Long userId = userRefresh.getUserId();
        return JwtHelper.createToken(userId);
    }

    /**
     * 返回用户的视频
     */
    @Override
    public PageVo<Video> getVideosByUserId(Integer page, Integer pageSize, Long userId) {

        return videoService.getVideosByUserId(page,pageSize,userId);
    }

    /**
     * 判空
     * @param <T> 具体的实体类
     */
    public static class Exist<T> {
        public boolean isExist(BaseMapper<T> o, String name, String val) {
            QueryWrapper<T> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(name, val);
            Long row = o.selectCount(queryWrapper);
            return row != 0;
        }

    }
}
